/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/18 10:40
  *
  * @file       pd_timer_encoder.c
  * @brief      Timer Encoder Interface peripheral driver.
  *
  * @note       This file contains the peripheral driver for the Timer Encoder
  *             Interface.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/18     Chris        the first version
  *
  ******************************************************************************
  */


#include <stm32f4xx_ll_tim.h>
#include <stm32f4xx_ll_gpio.h>
#include "pd_timer_encoder.h"

static void TimerEncoder_init_(const TimerEncoder *this) {
    // GPIO init
    GPIO *gpio = this->timerChannel->gpios;
    for (int i = 0; i < this->timerChannel->gpioSize; ++i) {
        gpio[i].Speed = LL_GPIO_SPEED_FREQ_HIGH;
        gpio[i].Mode = LL_GPIO_MODE_ALTERNATE;
        GPIO_init(&gpio[i]);
    }

    // Timer Base Unit
    Timer_init(this->timer);

    // Timer IC filter and edge polarity
    LL_TIM_IC_InitTypeDef TIM_IC_InitStruct = {0};
    LL_TIM_IC_StructInit(&TIM_IC_InitStruct);
    TIM_IC_InitStruct.ICFilter = 0xF;
    const uint32_t *channel = this->timerChannel->channels;
    for (int i = 0; i < this->timerChannel->chSize; ++i) {
        LL_TIM_IC_Init(this->timer->TIMx, channel[i], &TIM_IC_InitStruct);
    }

    // Encoder Interface
    LL_TIM_ENCODER_InitTypeDef TIM_ENCODER_InitStruct = {0};

    LL_TIM_ENCODER_StructInit(&TIM_ENCODER_InitStruct);
    TIM_ENCODER_InitStruct.EncoderMode = this->EncoderMode;

    TIM_ENCODER_InitStruct.IC1Polarity = this->IC1Polarity;
    TIM_ENCODER_InitStruct.IC1ActiveInput = this->IC1ActiveInput;
    TIM_ENCODER_InitStruct.IC1Prescaler = this->IC1Prescaler;
    TIM_ENCODER_InitStruct.IC1Filter = this->IC1Filter;

    TIM_ENCODER_InitStruct.IC2Polarity = this->IC2Polarity;
    TIM_ENCODER_InitStruct.IC2ActiveInput = this->IC2ActiveInput;
    TIM_ENCODER_InitStruct.IC2Prescaler = this->IC2Prescaler;
    TIM_ENCODER_InitStruct.IC2Filter = this->IC2Filter;
    LL_TIM_ENCODER_Init(this->timer->TIMx, &TIM_ENCODER_InitStruct);

    LL_TIM_EnableCounter(this->timer->TIMx);
}

static int16_t TimerEncoder_getCounter_(const TimerEncoder *this) {
    const int16_t temp = LL_TIM_GetCounter(this->timer->TIMx);
    LL_TIM_SetCounter(this->timer->TIMx, 0);
    return temp;
}

void TimerEncoder_constructor(TimerEncoder *this, Timer *timer, TimerCh *timerChannel) {
    static struct TimerEncoderVtbl vtbl = {
        .init = &TimerEncoder_init_,
        .get_counter = &TimerEncoder_getCounter_,
    };

    this->vptr = &vtbl;
    this->timer = timer;
    this->timerChannel = timerChannel;

    this->EncoderMode    = LL_TIM_ENCODERMODE_X4_TI12;
    this->IC1Polarity    = LL_TIM_IC_POLARITY_RISING;
    this->IC1ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
    this->IC1Prescaler   = LL_TIM_ICPSC_DIV1;
    this->IC1Filter      = LL_TIM_IC_FILTER_FDIV1;
    this->IC2Polarity    = LL_TIM_IC_POLARITY_RISING;
    this->IC2ActiveInput = LL_TIM_ACTIVEINPUT_DIRECTTI;
    this->IC2Prescaler   = LL_TIM_ICPSC_DIV1;
    this->IC2Filter      = LL_TIM_IC_FILTER_FDIV1;
}
